#pragma once


namespace SD_Tools
{
	enum SD_PixelFormat
	{
		PIXEL_FORMAT_32BPP,
		PIXEL_FORMAT_16BPP_R5G6B5,
		PIXEL_FORMAT_16BPP_R5G5B5,
		PIXEL_FORMAT_UYVY,
		PIXEL_FORMAT_YUY2,

		PIXEL_FORMAT_UNSUPPORTED,

		PIXEL_FORMAT_FIRST = PIXEL_FORMAT_32BPP,
		PIXEL_FORMAT_LAST = PIXEL_FORMAT_YUY2
	};

	enum SD_BlitterFormat
	{
		BLITTER_FORMAT_32BPP,
		BLITTER_FORMAT_16BPP,
		BLITTER_FORMAT_UYVY,
		BLITTER_FORMAT_YUY2,

		BLITTER_FORMAT_UNSUPPORTED
	};

	enum SDHW_RSLT
	{
		SDDO_OK = 0,
		SDDO_FAIL,
		SDDO_INTERFACE_CREATION_FAILED,
		SDDO_GETCAPS_FAILED,
		SDDO_OVERLAY_NOT_SUPPORTED,
		SDDO_PRIMARY_SURFACE_CREATION_FAILED,
		SDDO_OVERLAY_SURFACE_CREATION_FAILED,
		SDDO_BACK_SURFACE_CREATION_FAILED,
		SDDO_UNKNOWN_PIXELFORMAT,
		SDDO_UNKNOWN_BLITTERFORMAT,
		SDDO_PIXEL_FORMAT_NOT_SUPPORTED,
		SDDO_BLITTER_FORMAT_NOT_SUPPORTED,
		SDDO_EXCLUSIVE_MODE_SET,
		SDDO_DISPLAY_MODE_CHANGED,
		SDDO_SURFACE_RESTORING_FAILED,
		SDDO_OVERLAY_FLIP_FAILED,
		SDDO_OVERLAY_UPDATE_FAILED,
		SDDO_GETDC_FAILED,
		SDDO_BACK_SURFACE_LOCK_FAILED,
		SDDO_BACK_SURFACE_UNLOCK_FAILED,
		SDDO_RELOAD_FAILED,
		SDDO_BACK_SURFACE_RELEASE_FAILED,
		SDDO_OVERLAY_SURFACE_RELEASE_FAILED,
		SDDO_PRIMARY_SURFACE_RELEASE_FAILED,
		SDDO_INTERFACE_RELEASE_FAILED,
		SDDO_GET_BACKSURFACE_DESC_FAILED,
		SDDO_OUT_OF_BOUNDS,
		SDDO_BITMAP_LOCK_FAILED,
		SDDO_BITMAP_UNLOCK_FAILED,
		SDDO_BITMAP_BLIT_FAILED,
		SDDO_SURFACE_LOST,
		SDDO_GENERIC,
		SDDO_UNDEFINED,

		SDDO_SUCCESS = SDDO_OK
	};

	struct YUVColor
	{
		BYTE y;
		BYTE u;
		BYTE v;
	};

	struct RGBColor
	{
		BYTE Red;
		BYTE Green;
		BYTE Blue;
	};

	struct ImageRGB24
	{
		RGBColor* Pixel;
		UINT Width;
		UINT Height;
	};


	class SDGDIColor
	{
	private:

	public:
		Gdiplus::SolidBrush* MySolidBrush;
		Gdiplus::Pen* MyPen;
	private:

	public:
		SDGDIColor(DWORD ARGB);
		SDGDIColor(DWORD ARGB, float Size);
		~SDGDIColor();
	};

	SDGDIColor::SDGDIColor(DWORD ARGB)
	{
		MySolidBrush = new Gdiplus::SolidBrush(Gdiplus::Color(General::ARGBToABGR(ARGB)));
		MyPen = new Gdiplus::Pen(Gdiplus::Color(General::ARGBToABGR(ARGB)), 1.0f);
	}

	SDGDIColor::SDGDIColor(DWORD ARGB, float Size)
	{
		MySolidBrush = new Gdiplus::SolidBrush(Gdiplus::Color(General::ARGBToABGR(ARGB)));
		MyPen = new Gdiplus::Pen(Gdiplus::Color(General::ARGBToABGR(ARGB)), Size);
	}

	SDGDIColor::~SDGDIColor()
	{
		delete MySolidBrush;
		delete MyPen;
	}


	class GDIHardwareOverlayWrapper
	{
	private:
		IDirectDraw7* Interface;
		IDirectDrawSurface7* PrimarySurface;
		IDirectDrawSurface7* OverlaySurface;
		IDirectDrawSurface7* BackSurface;
		DDCAPS Caps;
		DDOVERLAYFX OverlayFX;
		DDSURFACEDESC2 BackSurfaceDesc;

		bool Active;
		bool SurfaceLost;
		DWORD OverlayFlags;

		RECT DestRect;
		Rectangle2 OverlayRect;

		SD_PixelFormat PixelFormat;
		SD_BlitterFormat BlitterFormat;

		Gdiplus::Bitmap* MyBitmap;
		Gdiplus::BitmapData* MyBitmapData;
		Gdiplus::Graphics* MyGraphics;
		ImageRGB24 MyImage;
		Gdiplus::Rect RenderRect;
		DWORD GdiStartupToken;

	public:
	private:
		SDHW_RSLT CreatePrimarySurface();
		SDHW_RSLT CreateOverlaySurface();
		SDHW_RSLT CreateBackSurface();
		SDHW_RSLT GetBlitterFormat(SD_BlitterFormat* BlitterFormat);
		DDPIXELFORMAT PixelFormatToDdPixelFormat(SD_PixelFormat format);
		SDHW_RSLT BlitImage(ImageRGB24 Image);
		SDHW_RSLT BlitUYVYImage(ImageRGB24 Image);
		SDHW_RSLT BlitYUY2Image(ImageRGB24 Image);
		SDHW_RSLT Blit32BPPImage(ImageRGB24 Image);
		SDHW_RSLT Blit16BPPImage(ImageRGB24 Image);
		YUVColor RGBToUYVY(RGBColor RGB);
		int ClampColor(int value, int low, int high);
		void CleanUp();

	public:
		GDIHardwareOverlayWrapper(Rectangle2& Rect);
		~GDIHardwareOverlayWrapper();
		SDHW_RSLT Init();
		SDHW_RSLT IsSupported();
		SDHW_RSLT BeginScene();
		SDHW_RSLT EndScene();
		SDHW_RSLT Present();
		SDHW_RSLT ReCreate();
		SDHW_RSLT RestoreSurfaces();
		Gdiplus::Graphics* GetRenderGraphics();
		Gdiplus::Bitmap* GetRenderBitmap();
	};

	GDIHardwareOverlayWrapper::GDIHardwareOverlayWrapper( Rectangle2& Rect )
	{
		Gdiplus::GdiplusStartupInput GdiStartupInp;
		Gdiplus::GdiplusStartup(&GdiStartupToken, &GdiStartupInp, NULL);

		MyBitmap = new Gdiplus::Bitmap((int) Rect.w, (int) Rect.h);
		MyBitmapData = new Gdiplus::BitmapData;
		MyBitmapData->Scan0 = (void*) new RGBColor[(int) (Rect.w*Rect.h)];
		MyBitmapData->Height = (UINT) Rect.h;
		MyBitmapData->Width = (UINT) Rect.w;
		MyBitmapData->PixelFormat = PixelFormat24bppRGB;
		MyBitmapData->Stride = (UINT) (Rect.w * 3);
		MyGraphics = Gdiplus::Graphics::FromImage(MyBitmap);
		MyGraphics->SetSmoothingMode(Gdiplus::SmoothingModeHighQuality);
		MyImage.Pixel = (RGBColor*) MyBitmapData->Scan0;
		MyImage.Width = (UINT) Rect.w;
		MyImage.Height = (UINT) Rect.h;
		RenderRect.X = 0;
		RenderRect.Y = 0;
		RenderRect.Width = (UINT) Rect.w;
		RenderRect.Height = (UINT) Rect.h;
		DestRect.top = (UINT) Rect.y;
		DestRect.left = (UINT) Rect.x;
		DestRect.bottom = (UINT) (Rect.y + Rect.h);
		DestRect.right = (UINT) (Rect.x + Rect.w);
		OverlayRect = Rect;
		OverlayFlags = DDOVER_SHOW;
	}

	GDIHardwareOverlayWrapper::~GDIHardwareOverlayWrapper()
	{
		if (BackSurface)
		{
			BackSurface->Release();
		}
		if (OverlaySurface)
		{
			OverlaySurface->Release();
		}
		if (PrimarySurface)
		{
			PrimarySurface->Release();
		}
		if (Interface)
		{
			Interface->Release();
		}
		CleanUp();
		delete MyBitmap;
		delete[] MyBitmapData->Scan0;
		delete MyBitmapData;
		Gdiplus::GdiplusShutdown(GdiStartupToken);
	}

	SD_Tools::SDHW_RSLT GDIHardwareOverlayWrapper::Init()
	{
		SDHW_RSLT Rslt = SDDO_FAIL;
		if (DirectDrawCreateEx(NULL, (void**) &Interface, IID_IDirectDraw7, NULL) == DD_OK)
		{
			if (Interface->SetCooperativeLevel(NULL, DDSCL_NORMAL) == DD_OK)
			{
				ZeroMemory(&Caps, sizeof(Caps));
				Caps.dwSize = sizeof(Caps);
				if (Interface->GetCaps(&Caps, NULL) == DD_OK)
				{
					ZeroMemory(&OverlayFX, sizeof(OverlayFX));
					OverlayFX.dwSize = sizeof(OverlayFX);
					if (CreatePrimarySurface() == SDDO_OK)
					{
						if (CreateOverlaySurface() == SDDO_OK)
						{
							if (CreateBackSurface() == SDDO_OK)
							{
								if (GetBlitterFormat(&BlitterFormat) == SDDO_OK)
								{
									OverlayFlags = DDOVER_SHOW;
									Rslt = SDDO_OK;
								}
							}
							else
							{
								Rslt = SDDO_BACK_SURFACE_CREATION_FAILED;
							}
						}
						else
						{
							Rslt = SDDO_OVERLAY_SURFACE_CREATION_FAILED;
						}
					}
					else
					{
						Rslt = SDDO_PRIMARY_SURFACE_CREATION_FAILED;
					}
				}
				else
				{
					Rslt = SDDO_GETCAPS_FAILED;
				}
			}
			else
			{
				Rslt = SDDO_OVERLAY_NOT_SUPPORTED;
			}
		}
		else
		{
			Rslt = SDDO_INTERFACE_CREATION_FAILED;
		}
		return Rslt;
	}

	SD_Tools::SDHW_RSLT GDIHardwareOverlayWrapper::IsSupported()
	{
		if (Caps.dwCaps & DDCAPS_OVERLAY)
		{
			return SDDO_OK;
		}
		return SDDO_OVERLAY_NOT_SUPPORTED;
	}

	SD_Tools::SDHW_RSLT GDIHardwareOverlayWrapper::BeginScene()
	{
		SDHW_RSLT Rslt = SDDO_FAIL;

		DDSURFACEDESC2 BackSurfaceDesc;
		ZeroMemory(&BackSurfaceDesc, sizeof(BackSurfaceDesc));
		BackSurfaceDesc.dwSize = sizeof(BackSurfaceDesc);

		if (BackSurface->Lock(NULL, &BackSurfaceDesc, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, 0) == DD_OK)
		{
			BYTE* DrawSurface = (BYTE*) BackSurfaceDesc.lpSurface;
			ZeroMemory(DrawSurface, BackSurfaceDesc.dwHeight*BackSurfaceDesc.lPitch);
			if (BackSurface->Unlock(NULL) == DD_OK)
			{
				Rslt = SDDO_OK;
			}
			else
			{
				Rslt = SDDO_BACK_SURFACE_UNLOCK_FAILED;
			}
		}
		else
		{
			Rslt = SDDO_BACK_SURFACE_LOCK_FAILED;
		}
		return Rslt;
	}

	SD_Tools::SDHW_RSLT GDIHardwareOverlayWrapper::EndScene()
	{
		SDHW_RSLT Rslt = SDDO_FAIL;

		if (MyBitmap->LockBits(&RenderRect, Gdiplus::ImageLockModeRead | Gdiplus::ImageLockModeUserInputBuf, PixelFormat24bppRGB, MyBitmapData) == Gdiplus::Ok)
		{
			MyImage.Pixel = (RGBColor*) MyBitmapData->Scan0;
			if (BlitImage(MyImage) == SDDO_OK)
			{
				Rslt = SDDO_OK;
			}
			else
			{
				Rslt = SDDO_BITMAP_BLIT_FAILED;
			}
			MyBitmap->UnlockBits(MyBitmapData);
		}
		else
		{
			Rslt = SDDO_BITMAP_LOCK_FAILED;
		}
		return Rslt;
	}

	SD_Tools::SDHW_RSLT GDIHardwareOverlayWrapper::Present()
	{
		SDHW_RSLT Rslt = SDDO_FAIL;

		HRESULT hr;

		hr = Interface->TestCooperativeLevel();
		if (hr != DD_OK)
		{
			switch (hr)
			{
			case DDERR_EXCLUSIVEMODEALREADYSET:
				{
					//RestoreSurfaces();
					//printf("Test...\n")
					; // Do Nothing...
				}
				break;
			case DDERR_WRONGMODE:
				{
					Rslt = SDDO_GENERIC;
					return Rslt;
				}
				break;
			default:
				Rslt = SDDO_GENERIC;
				return Rslt;
			}
		}

		if (PrimarySurface->IsLost() == DD_OK)
		{
			if (OverlaySurface->Flip(NULL, DDFLIP_WAIT) == DD_OK)
			{
				if (OverlaySurface->UpdateOverlay(NULL, PrimarySurface, &DestRect, OverlayFlags, &OverlayFX) == DD_OK)
				{
					if (OverlaySurface->UpdateOverlayZOrder(DDOVERZ_SENDTOFRONT, 0) == DD_OK)
					{
						Rslt = SDDO_OK;
					}
					else
					{
						Rslt = SDDO_UNDEFINED;
					}
				}
				else
				{
					Rslt = SDDO_OVERLAY_UPDATE_FAILED;
				}
			}
			else
			{
				Rslt = SDDO_OVERLAY_FLIP_FAILED;
			}
		}
		else
		{
			Rslt = SDDO_SURFACE_LOST;
		}

		return Rslt;
	}

	SD_Tools::SDHW_RSLT GDIHardwareOverlayWrapper::RestoreSurfaces()
	{
		SDHW_RSLT Rslt = SDDO_FAIL;

		if (Interface->RestoreDisplayMode() == DD_OK)
		{
			if (Interface->RestoreAllSurfaces() == DD_OK)
			{
				Rslt = SDDO_OK;
			}
			else
			{
				Rslt = SDDO_SURFACE_RESTORING_FAILED;
			}
		}
		else
		{
			Rslt = SDDO_UNDEFINED;
		}

		return Rslt;
	}
	
	Gdiplus::Graphics* GDIHardwareOverlayWrapper::GetRenderGraphics()
	{
		return MyGraphics;
	}

	Gdiplus::Bitmap* GDIHardwareOverlayWrapper::GetRenderBitmap()
	{
		return MyBitmap;
	}

	SD_Tools::SDHW_RSLT GDIHardwareOverlayWrapper::CreatePrimarySurface()
	{
		SDHW_RSLT Rslt = SDDO_FAIL;

		DDSURFACEDESC2 SurfaceDesc;
		ZeroMemory(&SurfaceDesc,sizeof(SurfaceDesc));
		SurfaceDesc.dwSize = sizeof(SurfaceDesc);
		SurfaceDesc.dwFlags = DDSD_CAPS;
		SurfaceDesc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;

		if (Interface->CreateSurface(&SurfaceDesc, &PrimarySurface, NULL) == DD_OK)
		{
			Rslt = SDDO_OK;
		}
		else
		{
			Rslt = SDDO_PRIMARY_SURFACE_CREATION_FAILED;
		}
		return Rslt;
	}

	SD_Tools::SDHW_RSLT GDIHardwareOverlayWrapper::CreateOverlaySurface()
	{
		SDHW_RSLT Rslt = SDDO_FAIL;

		DDSURFACEDESC2 SurfaceDesc;
		HRESULT hr;
		ZeroMemory(&SurfaceDesc, sizeof(SurfaceDesc));
		SurfaceDesc.dwSize = sizeof(SurfaceDesc);
		SurfaceDesc.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_BACKBUFFERCOUNT | DDSD_PIXELFORMAT;
		SurfaceDesc.ddsCaps.dwCaps = DDSCAPS_OVERLAY | DDSCAPS_FLIP | DDSCAPS_COMPLEX | DDSCAPS_VIDEOMEMORY;
		SurfaceDesc.dwBackBufferCount = 1;
		SurfaceDesc.dwWidth = (UINT) OverlayRect.w;
		SurfaceDesc.dwHeight = (UINT) OverlayRect.h;

		for(int Format = PIXEL_FORMAT_FIRST; Format <= PIXEL_FORMAT_LAST; Format++)
		{
			// Attempt to create the surface with this pixel format
			SurfaceDesc.ddpfPixelFormat = PixelFormatToDdPixelFormat((SD_PixelFormat) Format);
			hr = Interface->CreateSurface(&SurfaceDesc, &OverlaySurface, 0);
			if(SUCCEEDED(hr))
			{
				PixelFormat = (SD_PixelFormat) Format;
				break;
			}
		}

		if (PixelFormat != PIXEL_FORMAT_UNSUPPORTED)
		{
			Rslt = SDDO_OK;
		}
		else
		{
			Rslt = SDDO_PIXEL_FORMAT_NOT_SUPPORTED;
		}

		return Rslt;
	}

	SD_Tools::SDHW_RSLT GDIHardwareOverlayWrapper::CreateBackSurface()
	{
		SDHW_RSLT Rslt = SDDO_FAIL;
		DDSCAPS2 TempCaps;

		ZeroMemory(&TempCaps, sizeof(TempCaps));
		TempCaps.dwCaps = DDSCAPS_BACKBUFFER;

		if (OverlaySurface->GetAttachedSurface(&TempCaps, &BackSurface) == DD_OK)
		{
			Rslt = SDDO_OK;
		}
		else
		{
			Rslt = SDDO_BACK_SURFACE_CREATION_FAILED;
		}
		return Rslt;
	}

	SD_Tools::SDHW_RSLT GDIHardwareOverlayWrapper::GetBlitterFormat( SD_BlitterFormat* BlitterFormat )
	{
		SDHW_RSLT Rslt = SDDO_FAIL;

		DDSURFACEDESC2 SurfaceDesc;
		ZeroMemory(&SurfaceDesc, sizeof(SurfaceDesc));
		SurfaceDesc.dwSize = sizeof(SurfaceDesc);

		if (BackSurface->Lock(0, &SurfaceDesc, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, 0) == DD_OK)
		{
			BackSurfaceDesc = SurfaceDesc;
			BackSurface->Unlock(NULL);

			if(SurfaceDesc.ddpfPixelFormat.dwFlags == DDPF_FOURCC)
			{
				const DWORD fourCC = SurfaceDesc.ddpfPixelFormat.dwFourCC;
				if(fourCC == MAKEFOURCC('Y', 'U', 'Y', '2'))
					*BlitterFormat = BLITTER_FORMAT_YUY2;
				else if(fourCC == MAKEFOURCC('U', 'Y', 'V', 'Y'))
					*BlitterFormat = BLITTER_FORMAT_UYVY;
				Rslt = SDDO_OK;
			}
			else if(SurfaceDesc.ddpfPixelFormat.dwFlags == DDPF_RGB)
			{
				const DWORD bpp = SurfaceDesc.ddpfPixelFormat.dwRGBBitCount;
				if(bpp == 32)
					*BlitterFormat = BLITTER_FORMAT_32BPP;
				else if(bpp == 16)
					*BlitterFormat = BLITTER_FORMAT_16BPP;
				Rslt = SDDO_OK;
			}
			else
			{
				Rslt = SDDO_UNKNOWN_BLITTERFORMAT;
			}
		}
		else
		{
			Rslt = SDDO_BACK_SURFACE_LOCK_FAILED;
		}

		return Rslt;
	}

	DDPIXELFORMAT GDIHardwareOverlayWrapper::PixelFormatToDdPixelFormat( SD_PixelFormat format )
	{
		const DDPIXELFORMAT formats[] = 
		{
			// PIXEL_FORMAT_32BPP
			{ sizeof(DDPIXELFORMAT), DDPF_RGB, 0, 32, 0xFF0000, 0x0000FF00, 0x000000FF, 0},
			// PIXEL_FORMAT_16BPP_R5G6B5
			{ sizeof(DDPIXELFORMAT), DDPF_RGB, 0, 16, 0xF800, 0x07E0, 0x001F, 0},
			// PIXEL_FORMAT_16BPP_R5G5B5		
			{ sizeof(DDPIXELFORMAT), DDPF_RGB, 0, 16, 0x7C00, 0x03e0, 0x001F, 0},
			// PIXEL_FORMAT_UYVY
			{ sizeof(DDPIXELFORMAT), DDPF_FOURCC, MAKEFOURCC('U', 'Y', 'V', 'Y'), 0, 0, 0, 0, 0},
			// PIXEL_FORMAT_YUY2
			{ sizeof(DDPIXELFORMAT), DDPF_FOURCC, MAKEFOURCC('Y', 'U', 'Y', '2'), 0, 0, 0, 0, 0}
		};

		switch(format)
		{
		case PIXEL_FORMAT_32BPP:
			return formats[0];
		case PIXEL_FORMAT_16BPP_R5G6B5:
			return formats[1];
		case PIXEL_FORMAT_16BPP_R5G5B5:
			return formats[2];
		case PIXEL_FORMAT_UYVY:
			return formats[3];
		case PIXEL_FORMAT_YUY2:
			return formats[4];
		}
		return formats[0];
	}

	SD_Tools::SDHW_RSLT GDIHardwareOverlayWrapper::ReCreate()
	{
		if (BackSurface)
		{
			BackSurface->Release();
		}
		if (OverlaySurface)
		{
			OverlaySurface->Release();
		}
		if (PrimarySurface)
		{
			PrimarySurface->Release();
		}
		if (Interface)
		{
			Interface->Release();
		}
		CleanUp();
		return Init();
	}

	SD_Tools::SDHW_RSLT GDIHardwareOverlayWrapper::BlitImage( ImageRGB24 Image )
	{
		switch (BlitterFormat)
		{
		case BLITTER_FORMAT_32BPP:
			return Blit32BPPImage(Image);
		case BLITTER_FORMAT_16BPP:
			return Blit16BPPImage(Image);
		case BLITTER_FORMAT_UYVY:
			return BlitUYVYImage(Image);
		case BLITTER_FORMAT_YUY2:
			return BlitYUY2Image(Image);
		}
		return SDDO_BLITTER_FORMAT_NOT_SUPPORTED;
	}

	SD_Tools::SDHW_RSLT GDIHardwareOverlayWrapper::BlitUYVYImage( ImageRGB24 Image )
	{
		SDHW_RSLT Rslt = SDDO_FAIL;
		int x = 0;
		int y = 0;

		if (BackSurface->Lock(NULL, &BackSurfaceDesc, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, NULL) == DD_OK)
		{
			UINT TargetWidth = BackSurfaceDesc.dwWidth;
			UINT TargetHeight = BackSurfaceDesc.dwHeight;
			int Pitch = BackSurfaceDesc.lPitch;

			BYTE* DrawSurface = (BYTE*) BackSurfaceDesc.lpSurface;

			YUVColor YUVC0 = {0};
			YUVColor YUVC1 = {0};
			UINT16* line = 0;
			BYTE* macroPixel = 0;

			for (UINT i = y, yIndex = 0; i < y+Image.Height; i++, yIndex++)
			{
				line = (UINT16*) (DrawSurface + i * Pitch);
				for (UINT j = x, xIndex = 0; j < x+Image.Width; j+=2, xIndex+=2)
				{
					YUVC0 = RGBToUYVY(Image.Pixel[yIndex*Image.Width + xIndex]);
					YUVC1 = RGBToUYVY(Image.Pixel[yIndex*Image.Width + xIndex + 1]);

					macroPixel = (BYTE*) (line+j);
					*macroPixel++ = (YUVC0.u + YUVC1.u) / 2;
					*macroPixel++ = YUVC0.y;
					*macroPixel++ = (YUVC0.v + YUVC1.v) / 2;
					*macroPixel++ = YUVC1.y;
				}
			}
			BackSurface->Unlock(NULL);
			Rslt = SDDO_OK;
		}
		else
		{
			Rslt = SDDO_BACK_SURFACE_LOCK_FAILED;
		}

		return Rslt;
	}

	SD_Tools::SDHW_RSLT GDIHardwareOverlayWrapper::BlitYUY2Image( ImageRGB24 Image )
	{
		SDHW_RSLT Rslt = SDDO_FAIL;
		int x = 0;
		int y = 0;

		if (BackSurface->Lock(NULL, &BackSurfaceDesc, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, NULL) == DD_OK)
		{
			UINT TargetWidth = BackSurfaceDesc.dwWidth;
			UINT TargetHeight = BackSurfaceDesc.dwHeight;
			int Pitch = BackSurfaceDesc.lPitch;

			BYTE* DrawSurface = (BYTE*) BackSurfaceDesc.lpSurface;

			YUVColor YUVC0 = {0};
			YUVColor YUVC1 = {0};
			UINT16* line = 0;
			BYTE* macroPixel = 0;

			for (UINT i = y, yIndex = 0; i < y+Image.Height; i++, yIndex++)
			{
				line = (UINT16*) (DrawSurface + i * Pitch);
				for (UINT j = x, xIndex = 0; j < x+Image.Width; j+=2, xIndex+=2)
				{
					YUVC0 = RGBToUYVY(Image.Pixel[yIndex*Image.Width + xIndex]);
					YUVC1 = RGBToUYVY(Image.Pixel[yIndex*Image.Width + xIndex + 1]);

					macroPixel = (BYTE*) (line+j);
					*macroPixel++ = YUVC0.y;
					*macroPixel++ = (YUVC0.u + YUVC1.u) / 2;
					*macroPixel++ = YUVC1.y;
					*macroPixel++ = (YUVC0.v + YUVC1.v) / 2;
				}
			}
			BackSurface->Unlock(NULL);
			Rslt = SDDO_OK;
		}
		else
		{
			Rslt = SDDO_BACK_SURFACE_LOCK_FAILED;
		}

		return Rslt;
	}

	SD_Tools::SDHW_RSLT GDIHardwareOverlayWrapper::Blit32BPPImage( ImageRGB24 Image )
	{
		SDHW_RSLT Rslt = SDDO_FAIL;
		int x = 0;
		int y = 0;

		if (BackSurface->Lock(NULL, &BackSurfaceDesc, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, NULL) == DD_OK)
		{
			UINT TargetWidth = BackSurfaceDesc.dwWidth;
			UINT TargetHeight = BackSurfaceDesc.dwHeight;
			int Pitch = BackSurfaceDesc.lPitch;

			if (x + Image.Width > TargetWidth || y + Image.Height > TargetHeight)
				return SDDO_OUT_OF_BOUNDS;

			BYTE* DrawSurface = (BYTE*) BackSurfaceDesc.lpSurface;

			UINT32* line = 0;

			for (UINT i = y, yIndex = 0; i < y+Image.Height; i++, yIndex++)
			{
				line = (UINT32*) (DrawSurface + i * Pitch);
				for (UINT j = x, xIndex = 0; j < x+Image.Width; j++, xIndex++)
				{
					line[j] = (Image.Pixel[yIndex*Image.Width + xIndex].Red << 16) | (Image.Pixel[yIndex*Image.Width + xIndex].Green << 8) | (Image.Pixel[yIndex*Image.Width + xIndex].Blue);
				}
			}

			BackSurface->Unlock(NULL);
			Rslt = SDDO_OK;
		}
		else
		{
			Rslt = SDDO_BACK_SURFACE_LOCK_FAILED;
		}

		return Rslt;
	}

	SD_Tools::SDHW_RSLT GDIHardwareOverlayWrapper::Blit16BPPImage( ImageRGB24 Image )
	{
		SDHW_RSLT Rslt = SDDO_FAIL;
		int x = 0;
		int y = 0;

		if (BackSurface->Lock(NULL, &BackSurfaceDesc, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, NULL) == DD_OK)
		{
			BackSurface->Unlock(NULL);
			Rslt = SDDO_OK;
		}
		else
		{
			Rslt = SDDO_BACK_SURFACE_LOCK_FAILED;
		}

		UINT TargetWidth = BackSurfaceDesc.dwWidth;
		UINT TargetHeight = BackSurfaceDesc.dwHeight;
		int Pitch = BackSurfaceDesc.lPitch;

		if (x + Image.Width > TargetWidth || y + Image.Height > TargetHeight)
			return SDDO_OUT_OF_BOUNDS;

		BYTE* DrawSurface = (BYTE*) BackSurfaceDesc.lpSurface;

		UINT16* line = 0;
		BYTE* macroPixel = 0;

		for (UINT i = y, yIndex = 0; i < y+Image.Height; i++, yIndex++)
		{
			line = (UINT16*) (DrawSurface + i * Pitch);
			for (UINT j = x, xIndex = 0; j < x+Image.Width; j++, xIndex++)
			{
				if (PixelFormat == PIXEL_FORMAT_16BPP_R5G6B5)
				{
					line[j] = ((Image.Pixel[yIndex*Image.Width + xIndex].Red >> 3) << 11) | ((Image.Pixel[yIndex*Image.Width + xIndex].Green >> 2) << 5) | (Image.Pixel[yIndex*Image.Width + xIndex].Blue >> 3);
				}
				else
				{
					line[j] = ((Image.Pixel[yIndex*Image.Width + xIndex].Red >> 3) << 10) | ((Image.Pixel[yIndex*Image.Width + xIndex].Green >> 3) << 5) | (Image.Pixel[yIndex*Image.Width + xIndex].Blue >> 3);
				}
			}
		}

		return Rslt;
	}

	SD_Tools::YUVColor GDIHardwareOverlayWrapper::RGBToUYVY( RGBColor RGB )
	{
		YUVColor result =
		{
			ClampColor((int)(0.29f * RGB.Red + 0.59f * RGB.Green + 0.14f * RGB.Blue), 0, 235),
			ClampColor((int)(128.0f - 0.14f * RGB.Red - 0.29f * RGB.Green + 0.43f * RGB.Blue), 0, 240),
			ClampColor((int)(128.0f + 0.36f * RGB.Red - 0.29f * RGB.Green - 0.07f * RGB.Blue), 0, 240)
		};

		return result;
	}

	int GDIHardwareOverlayWrapper::ClampColor( int value, int low, int high )
	{
		if(value < low)
			return low;
		else if(value > high)
			return high;

		return value;
	}

	void GDIHardwareOverlayWrapper::CleanUp()
	{
		OverlaySurface = NULL;
		PrimarySurface = NULL;
		BackSurface = NULL;
		Interface = NULL;

		PixelFormat = PIXEL_FORMAT_UNSUPPORTED;
		BlitterFormat = BLITTER_FORMAT_UNSUPPORTED;
		OverlayFlags = DDOVER_SHOW;
	}

};
















